package vip.xiaonuo.vehicle.common.reactor;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.Reactor;
import reactor.function.Consumer;
import reactor.event.Event;
import vip.xiaonuo.facedoor.modular.devicebase.entity.DeviceBase;
import vip.xiaonuo.facedoor.modular.devicehistory.entity.DeviceHistory;
import vip.xiaonuo.facedoor.modular.devicehistory.service.DeviceHistoryService;
import vip.xiaonuo.facedoor.modular.memberuser.entity.MemberUser;
import vip.xiaonuo.facedoor.modular.memberuser.service.MemberUserService;
import vip.xiaonuo.facedoor.modular.visitor.entity.Visitor;
import vip.xiaonuo.facedoor.modular.visitor.service.VisitorService;
import vip.xiaonuo.facedoor.modular.visitorhistory.entity.VisitorHistory;
import vip.xiaonuo.facedoor.modular.visitorhistory.service.VisitorHistoryService;
import vip.xiaonuo.sys.modular.org.entity.SysOrg;
import vip.xiaonuo.sys.modular.org.service.SysOrgService;
import vip.xiaonuo.vehicle.common.constant.Constants;
import vip.xiaonuo.vehicle.common.enums.PersonnelTypeEnum;
import vip.xiaonuo.vehicle.common.reactor.dto.RecorderDto;
import vip.xiaonuo.vehicle.common.util.SnowFlakeUtil;
import vip.xiaonuo.vehicle.common.util.transaction.TransactionUtils;
import vip.xiaonuo.vehicle.modular.vehicleinfo.entity.VehicleInfo;
import vip.xiaonuo.vehicle.modular.vehicletrafficrecord.entity.VehicleTrafficRecord;
import vip.xiaonuo.vehicle.modular.vehicletrafficrecord.service.VehicleTrafficRecordService;

import javax.annotation.Resource;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicReference;

import static reactor.event.selector.Selectors.$;

/**
 * 人员通行记录
 *
 * @author cad
 * @date 2023/03/23
 */
@Service
public class TrafficRecorder implements Consumer<Event<RecorderDto>>, InitializingBean {
    @Resource
    private Reactor reactor;
    @Resource
    private VisitorService visitorService;
    @Resource
    private SysOrgService sysOrgService;
    @Resource
    private VisitorHistoryService visitorHistoryService;
    @Resource
    private MemberUserService memberUserService;
    @Resource
    private DeviceHistoryService deviceHistoryService;
    @Resource
    private VehicleTrafficRecordService vehicleTrafficRecordService;
    @Resource
    private TransactionUtils transactionUtils;

    @Override
    public void afterPropertiesSet() {
        reactor.on($(Constants.RECORDER_TOPIC), this);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void accept(Event<RecorderDto> personnelRecorderDtoEvent) {
        RecorderDto data = personnelRecorderDtoEvent.getData();
        AtomicReference<Date> date = new AtomicReference<>(new Date());
        //线程屏障
        CyclicBarrier cb = new CyclicBarrier(1);
        //非阻塞原子类
        AtomicReference<Boolean> rollback = new AtomicReference<>(false);
        //保存通行记录
//        CompletableFuture.runAsync(() -> {
//            transactionUtils.multithreadedTransaction(
//                    () -> getPersonnelTrafficRecord(data.getDeviceBase(), data.getVehicleInfo(), data.getPersonType(), date.get()), cb, rollback);
//        });
        CompletableFuture.runAsync(() -> {
            transactionUtils.multithreadedTransaction(
                    () -> getVehicleTrafficRecord(data.getDeviceBase(), data.getVehicleInfo(), data.getImg(), data.getPersonType(), date.get()), cb, rollback);
        });
    }

    /**
     * 保存人员通行记录
     *
     * @param deviceBase  设备基础
     * @param vehicleInfo 车辆信息
     */
    private void getPersonnelTrafficRecord(DeviceBase deviceBase, VehicleInfo vehicleInfo, Integer personType, Date date) {
        Integer personnelType = Optional.ofNullable(personType).orElse(-1);
        switch (Objects.requireNonNull(PersonnelTypeEnum.getByFlag(personnelType))) {
            case VISITOR:
                List<Visitor> list = visitorService.list(new LambdaQueryWrapper<Visitor>().eq(Visitor::getCarNum, vehicleInfo.getLicensePlateNumber()));
                Visitor visitor = list.get(0);
                VisitorHistory visitorHistory = new VisitorHistory();
                visitorHistory.setDeviceName(deviceBase.getName());
                visitorHistory.setDeviceBaseId(deviceBase.getId());
                visitorHistory.setVisitorId(visitor.getId());
                visitorHistory.setDeviceCurrentDate(date);
                visitorHistory.setVisitorName(visitor.getName());
                if (ObjectUtil.isNotEmpty(visitor.getOrgId())) {
                    visitorHistory.setOrgId(visitor.getOrgId());
                    SysOrg sysOrg = sysOrgService.getById(visitor.getOrgId());
                    if (sysOrg != null) {
                        visitorHistory.setOrgName(sysOrg.getName());
                    }
                }
                visitorHistory.setVerifyType("1");
                visitorHistoryService.save(visitorHistory);
                break;
            case MEMBER_USER:
                MemberUser memberUser = memberUserService.getById(vehicleInfo.getPersonnelId());
                DeviceHistory deviceHistory = new DeviceHistory();
                deviceHistory.setDeviceName(deviceBase.getName());
                deviceHistory.setDeviceBaseId(deviceBase.getId());
                deviceHistory.setMemberId(memberUser.getId());
                deviceHistory.setDeviceCurrentDate(date);
                deviceHistory.setMemberName(memberUser.getName());
                deviceHistory.setOrgId(memberUser.getOrgId());
                deviceHistory.setVerifyType(Integer.valueOf("1"));
                deviceHistoryService.save(deviceHistory);
                break;
            default:
            case UNKNOWN:
                break;
        }
    }


    /**
     * 保存车辆通行通行记录
     *
     * @param deviceBase  设备
     * @param vehicleInfo 车辆信息
     * @param image       图像
     */
    private void getVehicleTrafficRecord(DeviceBase deviceBase, VehicleInfo vehicleInfo, String image, Integer
            personType, Date date) {
        VehicleTrafficRecord vehicleTrafficRecord = new VehicleTrafficRecord();
        vehicleTrafficRecord.setId(SnowFlakeUtil.nextId());
        vehicleTrafficRecord.setPersonType(personType);
        vehicleTrafficRecord.setTrafficChannel(deviceBase.getName());
        vehicleTrafficRecord.setTrafficTime(date);
        vehicleTrafficRecord.setTrafficPhoto(image);
        if (Constants.ENTRANCE.equals(deviceBase.getInOut())) {
            vehicleTrafficRecord.setInOut(1);
        } else {
            vehicleTrafficRecord.setInOut(2);
        }
        vehicleTrafficRecord.setLicensePlateNumber(vehicleInfo.getLicensePlateNumber());
        vehicleTrafficRecordService.save(vehicleTrafficRecord);
    }
}
